home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / ADA / GNAT / !gcc / adainc / 2 / adb / a-stwima < prev    next >
Text File  |  1996-02-12  |  17KB  |  616 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                A D A . S T R I N G S . W I D E _ M A P S                 --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.9 $                              --
  10. --                                                                          --
  11. --   Copyright (C) 1992,1993,1994,1995,1996 Free Software Foundation, Inc.  --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. package body Ada.Strings.Wide_Maps is
  37.  
  38.    ---------
  39.    -- "=" --
  40.    ---------
  41.  
  42.    --  The sorted, discontiguous form is canonical, so equality can be used
  43.  
  44.    function "=" (Left, Right : in Wide_Character_Set) return Boolean is
  45.    begin
  46.       return Left.all = Right.all;
  47.    end "=";
  48.  
  49.    ---------
  50.    -- "-" --
  51.    ---------
  52.  
  53.    function "-"
  54.      (Left, Right : in Wide_Character_Set)
  55.       return        Wide_Character_Set
  56.    is
  57.       Result : Wide_Character_Ranges (1 .. Left'Length + Right'Length);
  58.       --  Each range on the right can generate at least one more range in
  59.       --  the result, by splitting one of the left operand ranges.
  60.  
  61.       N : Natural := 0;
  62.       R : Natural := 1;
  63.       W : Wide_Character;
  64.  
  65.    begin
  66.       --  Basic loop is through ranges of left set
  67.  
  68.       for L in Left'Range loop
  69.  
  70.          --  W is lowest element of current left range not dealt with yet
  71.  
  72.          W := Left (L).Low;
  73.  
  74.          --  Skip by ranges of right set that have no impact on us
  75.  
  76.          while R <= Right'Length and then Right (R).High < W loop
  77.             R := R + 1;
  78.          end loop;
  79.  
  80.          --  Deal with ranges on right that create holes in the left range
  81.  
  82.          while R <= Right'Length and then Right (R).High < Left (L).High loop
  83.             N := N + 1;
  84.             Result (N).Low  := W;
  85.             Result (N).High := Right (R).High;
  86.             R := R + 1;
  87.          end loop;
  88.  
  89.          --  Now we have to output the final piece of the left range if any
  90.  
  91.          if R <= Right'Length and then Right (R).Low <= Left (L).High then
  92.  
  93.             --  Current right range consumes all of the rest of left range
  94.  
  95.             if Right (R).Low < W then
  96.                null;
  97.  
  98.             --  Current right range consumes part of the rest of left range
  99.  
  100.             else
  101.                N := N + 1;
  102.                Result (N).Low  := W;
  103.                Result (N).High := Wide_Character'Pred (Right (R).Low);
  104.             end if;
  105.  
  106.          --  Rest of left range to be retained complete
  107.  
  108.          else
  109.             N := N + 1;
  110.             Result (N).Low  := W;
  111.             Result (N).High := Left (L).High;
  112.          end if;
  113.       end loop;
  114.  
  115.       return new Wide_Character_Ranges'(Result (1 .. N));
  116.    end "-";
  117.  
  118.    -----------
  119.    -- "and" --
  120.    -----------
  121.  
  122.    function "and"
  123.      (Left, Right : in Wide_Character_Set)
  124.       return        Wide_Character_Set
  125.    is
  126.       Result : Wide_Character_Ranges (1 .. Left.all'Length + Right.all'Length);
  127.       N      : Natural := 0;
  128.       L, R   : Natural := 1;
  129.  
  130.    begin
  131.       --  Loop to search for overlapping character ranges
  132.  
  133.       loop
  134.          exit when L > Left.all'Last;
  135.          exit when R > Right.all'Last;
  136.  
  137.          if Left (L).High < Right (R).Low then
  138.             L := L + 1;
  139.  
  140.          elsif Right (R).High < Left (L).Low then
  141.             R := R + 1;
  142.  
  143.          --  Here we have Left.High  >= Right.Low
  144.          --           and Right.High >= Left.Low
  145.          --  so we have an overlapping range
  146.  
  147.          else
  148.             N := N + 1;
  149.             Result (N).Low :=
  150.               Wide_Character'Max (Left (L).Low,  Right (R).Low);
  151.             Result (N).High :=
  152.               Wide_Character'Min (Left (L).High, Right (R).High);
  153.             if Right (R).High = Left (L).High then
  154.                L := L + 1;
  155.                R := R + 1;
  156.             elsif Right (R).High < Left (L).High then
  157.                R := R + 1;
  158.             else
  159.                L := L + 1;
  160.             end if;
  161.          end if;
  162.       end loop;
  163.  
  164.       return new Wide_Character_Ranges'(Result (1 .. N));
  165.    end "and";
  166.  
  167.    -----------
  168.    -- "not" --
  169.    -----------
  170.  
  171.    function "not"
  172.      (Right  : in Wide_Character_Set)
  173.       return Wide_Character_Set
  174.    is
  175.       Result : Wide_Character_Ranges (1 .. Right.all'Length + 1);
  176.       N      : Natural := 0;
  177.  
  178.    begin
  179.       if Right = Null_Set then
  180.          N := 1;
  181.          Result (1)
  182.            := (Low => Wide_Character'First, High => Wide_Character'Last);
  183.       else
  184.          if Right (1).Low /= Wide_Character'First then
  185.             N := N + 1;
  186.             Result (N).Low  := Wide_Character'First;
  187.             Result (N).High := Wide_Character'Pred (Right (1).Low);
  188.          end if;
  189.  
  190.          for K in 1 .. Right.all'Last - 1 loop
  191.             N := N + 1;
  192.             Result (N).Low  := Wide_Character'Succ (Right (K).High);
  193.             Result (N).High := Wide_Character'Pred (Right (K + 1).Low);
  194.          end loop;
  195.  
  196.          if Right (Right.all'Last).High /= Wide_Character'Last then
  197.             N := N + 1;
  198.             Result (N).Low  := Wide_Character'Succ (Right (Right'Last).High);
  199.             Result (N).High := Wide_Character'Pred (Right (1).Low);
  200.          end if;
  201.       end if;
  202.  
  203.       return new Wide_Character_Ranges'(Result (1 .. N));
  204.    end "not";
  205.  
  206.    ----------
  207.    -- "or" --
  208.    ----------
  209.  
  210.    function "or"
  211.      (Left, Right : in Wide_Character_Set)
  212.       return        Wide_Character_Set
  213.    is
  214.       Result : Wide_Character_Ranges (1 .. Left'Length + Right'Length);
  215.       N      : Natural;
  216.       L, R   : Natural;
  217.  
  218.    begin
  219.       if Left'Length = 0 then
  220.          return Right;
  221.  
  222.       elsif Right'Length = 0 then
  223.          return Left;
  224.  
  225.       else
  226.          N := 1;
  227.          Result (1) := Left (1);
  228.          L := 2;
  229.          R := 1;
  230.  
  231.          loop
  232.             --  Collapse next left range into current result range if possible
  233.  
  234.             if L <= Left'Length
  235.               and then Wide_Character'Pos (Left (L).Low) <=
  236.                        Wide_Character'Pos (Result (N).High) + 1
  237.             then
  238.                Result (N).High :=
  239.                  Wide_Character'Max (Result (N).High, Left (L).High);
  240.                L := L + 1;
  241.  
  242.             --  Collapse next right range into current result range if possible
  243.  
  244.             elsif R <= Right'Length
  245.               and then Wide_Character'Pos (Right (R).Low) <=
  246.                        Wide_Character'Pos (Result (N).High) + 1
  247.             then
  248.                Result (N).High :=
  249.                  Wide_Character'Max (Result (N).High, Right (R).High);
  250.                R := R + 1;
  251.  
  252.             --  Otherwise establish new result range
  253.  
  254.             else
  255.                if L <= Left'Length then
  256.                   N := N + 1;
  257.                   Result (N) := Left (L);
  258.                   L := L + 1;
  259.  
  260.                elsif R <= Right'Length then
  261.                   N := N + 1;
  262.                   Result (N) := Right (R);
  263.                   R := R + 1;
  264.  
  265.                else
  266.                   exit;
  267.                end if;
  268.             end if;
  269.          end loop;
  270.       end if;
  271.  
  272.       return new Wide_Character_Ranges'(Result (1 .. N));
  273.    end "or";
  274.  
  275.    -----------
  276.    -- "xor" --
  277.    -----------
  278.  
  279.    function "xor"
  280.      (Left, Right : in Wide_Character_Set)
  281.       return        Wide_Character_Set
  282.    is
  283.    begin
  284.       return (Left or Right) - (Left and Right);
  285.    end "xor";
  286.  
  287.    -----------
  288.    -- Is_In --
  289.    -----------
  290.  
  291.    function Is_In
  292.      (Element : in Wide_Character;
  293.       Set     : in Wide_Character_Set)
  294.       return    Boolean
  295.    is
  296.       L, R, M : Natural;
  297.  
  298.    begin
  299.       L := Set'First;
  300.       R := Set'Last;
  301.  
  302.       --  Binary search loop. The invariant is that if Element is in any of
  303.       --  of the constituent ranges it is in one between Set (L) and Set (R).
  304.  
  305.       loop
  306.          if L > R then
  307.             return False;
  308.  
  309.          else
  310.             M := (L + R) / 2;
  311.  
  312.             if Element > Set (M).High then
  313.                L := M + 1;
  314.             elsif Element < Set (M).Low then
  315.                R := M - 1;
  316.             else
  317.                return True;
  318.             end if;
  319.          end if;
  320.       end loop;
  321.    end Is_In;
  322.  
  323.    ---------------
  324.    -- Is_Subset --
  325.    ---------------
  326.  
  327.    function Is_Subset
  328.      (Elements : in Wide_Character_Set;
  329.       Set      : in Wide_Character_Set)
  330.       return     Boolean
  331.    is
  332.       S : Positive := 1;
  333.       E : Positive := 1;
  334.  
  335.    begin
  336.       loop
  337.          --  If no more element ranges, done, and result is true
  338.  
  339.          if E > Elements'Length then
  340.             return True;
  341.  
  342.          --  If more element ranges, but no more set ranges, result is false
  343.  
  344.          elsif S > Set'Length then
  345.             return False;
  346.  
  347.          --  Remove irrelevant set range
  348.  
  349.          elsif Set (S).High < Elements (E).Low then
  350.             S := S + 1;
  351.  
  352.          --  Get rid of element range that is properly covered by set
  353.  
  354.          elsif Set (S).Low <= Elements (E).Low
  355.             and then Elements (E).High <= Set (S).High
  356.          then
  357.             E := E + 1;
  358.  
  359.          --  Otherwise we have a non-covered element range, result is false
  360.  
  361.          else
  362.             return False;
  363.          end if;
  364.       end loop;
  365.    end Is_Subset;
  366.  
  367.    ---------------
  368.    -- To_Domain --
  369.    ---------------
  370.  
  371.    function To_Domain
  372.      (Map  : in Wide_Character_Mapping)
  373.       return Wide_Character_Sequence
  374.    is
  375.    begin
  376.       return Map.Domain.all;
  377.    end To_Domain;
  378.  
  379.    ----------------
  380.    -- To_Mapping --
  381.    ----------------
  382.  
  383.    function To_Mapping
  384.      (From, To : in Wide_Character_Sequence)
  385.       return     Wide_Character_Mapping
  386.    is
  387.       Domain : Wide_Character_Sequence (1 .. From'Length);
  388.       Rangev : Wide_Character_Sequence (1 .. To'Length);
  389.       N      : Natural := 0;
  390.       K      : Natural := 0;
  391.  
  392.    begin
  393.       if From'Length /= To'Length then
  394.          raise Translation_Error;
  395.  
  396.       else
  397.          for J in From'Range loop
  398.             for M in 1 .. N loop
  399.                if From (J) = Domain (M) then
  400.                   raise Translation_Error;
  401.                elsif From (J) < Domain (M) then
  402.                   Domain (M + 1 .. N + 1) := Domain (M .. N);
  403.                   Domain (M) := From (J);
  404.                   Rangev (M) := To   (J);
  405.                   goto Continue;
  406.                end if;
  407.             end loop;
  408.  
  409.             Domain (N + 1) := From (J);
  410.             Rangev (N + 1) := To   (J);
  411.  
  412.             <<Continue>>
  413.                N := N + 1;
  414.          end loop;
  415.  
  416.          return (Domain => new Wide_Character_Sequence'(Domain (1 .. N)),
  417.                  Rangev => new Wide_Character_Sequence'(Rangev (1 .. N)));
  418.       end if;
  419.    end To_Mapping;
  420.  
  421.    --------------
  422.    -- To_Range --
  423.    --------------
  424.  
  425.    function To_Range
  426.      (Map  : in Wide_Character_Mapping)
  427.       return Wide_Character_Sequence
  428.    is
  429.    begin
  430.       return Map.Rangev.all;
  431.    end To_Range;
  432.  
  433.    ---------------
  434.    -- To_Ranges --
  435.    ---------------
  436.  
  437.    function To_Ranges
  438.      (Set :  in Wide_Character_Set)
  439.       return Wide_Character_Ranges
  440.    is
  441.    begin
  442.       return Set.all;
  443.    end To_Ranges;
  444.  
  445.    -----------------
  446.    -- To_Sequence --
  447.    -----------------
  448.  
  449.    function To_Sequence
  450.      (Set  : in Wide_Character_Set)
  451.       return Wide_Character_Sequence
  452.    is
  453.       Result : Wide_String (Positive range 1 .. 2 ** 16);
  454.       N      : Natural := 0;
  455.  
  456.    begin
  457.       for J in Set'Range loop
  458.          for K in Set (J).Low .. Set (J).High loop
  459.             N := N + 1;
  460.             Result (N) := K;
  461.          end loop;
  462.       end loop;
  463.  
  464.       return Result (1 .. N);
  465.    end To_Sequence;
  466.  
  467.    ------------
  468.    -- To_Set --
  469.    ------------
  470.  
  471.    --  Case of multiple range input
  472.  
  473.    function To_Set
  474.      (Ranges : in Wide_Character_Ranges)
  475.       return   Wide_Character_Set
  476.    is
  477.       Result : Wide_Character_Ranges (Ranges'Range);
  478.       N      : Natural := 0;
  479.       J      : Natural;
  480.  
  481.    begin
  482.       --  The output of To_Set is required to be sorted by increasing Low
  483.       --  values, and discontiguous, so first we sort them as we enter them,
  484.       --  using a simple insertion sort.
  485.  
  486.       for J in Ranges'Range loop
  487.          for K in 1 .. N loop
  488.             if Ranges (J).Low < Result (K).Low then
  489.                Result (K + 1 .. N + 1) := Result (K .. N);
  490.                Result (K) := Ranges (J);
  491.                goto Continue;
  492.             end if;
  493.          end loop;
  494.  
  495.          Result (N + 1) := Ranges (J);
  496.  
  497.          <<Continue>>
  498.             N := N + 1;
  499.       end loop;
  500.  
  501.       --  Now collapse any contiguous or overlapping ranges
  502.  
  503.       J := 1;
  504.       while J < N loop
  505.          if Result (J).High < Result (J).Low then
  506.             N := N - 1;
  507.             Result (J .. N) := Result (J + 1 .. N + 1);
  508.  
  509.          elsif Wide_Character'Pos (Result (J).High) + 1 >=
  510.             Wide_Character'Pos (Result (J + 1).Low)
  511.          then
  512.             Result (J).High :=
  513.               Wide_Character'Max (Result (J).High, Result (J + 1).High);
  514.  
  515.             N := N - 1;
  516.             Result (J + 1 .. N) := Result (J + 2 .. N + 1);
  517.  
  518.          else
  519.             J := J + 1;
  520.          end if;
  521.       end loop;
  522.  
  523.       if Result (N).High > Result (N).Low then
  524.          N := N - 1;
  525.       end if;
  526.  
  527.       return new Wide_Character_Ranges'(Result (1 .. N));
  528.  
  529.    end To_Set;
  530.  
  531.    --  Case of single range input
  532.  
  533.    function To_Set
  534.      (Span : in Wide_Character_Range)
  535.       return Wide_Character_Set
  536.    is
  537.    begin
  538.       if Span.Low > Span.High then
  539.          return Null_Set;
  540.          --  This is safe, because there is no procedure with parameter
  541.          --  Wide_Character_Set on mode "out" or "in out".
  542.  
  543.       else
  544.          return new Wide_Character_Ranges'(1 => Span);
  545.       end if;
  546.    end To_Set;
  547.  
  548.    --  Case of wide string input
  549.  
  550.    function To_Set
  551.      (Sequence  : in Wide_Character_Sequence)
  552.       return      Wide_Character_Set
  553.    is
  554.       R : Wide_Character_Ranges (1 .. Sequence'Length);
  555.  
  556.    begin
  557.       for J in R'Range loop
  558.          R (J) := (Sequence (J), Sequence (J));
  559.       end loop;
  560.  
  561.       return To_Set (R);
  562.    end To_Set;
  563.  
  564.    --  Case of single wide character input
  565.  
  566.    function To_Set
  567.      (Singleton : in Wide_Character)
  568.       return      Wide_Character_Set
  569.    is
  570.    begin
  571.       return new Wide_Character_Ranges'(1 => (Singleton, Singleton));
  572.    end To_Set;
  573.  
  574.    -----------
  575.    -- Value --
  576.    -----------
  577.  
  578.    function Value
  579.      (Map     : in Wide_Character_Mapping;
  580.       Element : in Wide_Character)
  581.       return    Wide_Character
  582.    is
  583.       L, R, M : Natural;
  584.  
  585.    begin
  586.       L := 1;
  587.       R := Map.Domain'Last;
  588.  
  589.       --  Binary search loop
  590.  
  591.       loop
  592.          --  If not found, identity
  593.  
  594.          if L > R then
  595.             return Element;
  596.  
  597.          --  Otherwise do binary divide
  598.  
  599.          else
  600.             M := (L + R) / 2;
  601.  
  602.             if Element < Map.Domain (M) then
  603.                R := M - 1;
  604.  
  605.             elsif Element > Map.Domain (M) then
  606.                L := M + 1;
  607.  
  608.             else --  Element = Map.Domain (M) then
  609.                return Map.Rangev (M);
  610.             end if;
  611.          end if;
  612.       end loop;
  613.    end Value;
  614.  
  615. end Ada.Strings.Wide_Maps;
  616.